cbuffer cbCamera
{
    float4x4 InvTransformMatrix;
    float3 CameraPosition;
};

cbuffer cbPerObject
{
    float3 LightPosition;
    float3 Attenuation;
    float3 Color;
};

Texture2D<float> DepthBuffer;
Texture2D<float4> AlbedoBuffer;
Texture2D<float4> NormalVectorBuffer;

Texture2DMS<float> DepthBufferMSAA;
Texture2DMS<float4> AlbedoBufferMSAA;
Texture2DMS<float4> NormalVectorBufferMSAA;

struct VS_IN
{
    float4 Position : POSITION;
};

struct VS_OUT
{
    float2 TexCoord : TEXCOORD;
    float2 PositionRel : POSITION_REL;
    float4 Position : SV_POSITION;
};

VS_OUT VS(VS_IN vIn)
{
    VS_OUT vOut;
    vOut.TexCoord = mad(vIn.Position.xy, float2(0.5, -0.5), 0.5);
    vOut.Position = vIn.Position;
    vOut.PositionRel = vIn.Position.xy;
    return vOut;
}

float4 LitGBuffer(float4 pos_screen, float4 albedo_buf, float4 normal_buf)
{
    float4 position = mul(pos_screen, InvTransformMatrix);
    float3 pos = position.xyz/position.w;
    float3 light = LightPosition - pos;
    float dist = length(light);
    light = normalize(light);
    
    float att = dot(float3(1.0, dist, dist*dist), Attenuation);
    float3 normal = 2.0*normal_buf.xyz - 1.0;
    float specular = albedo_buf.w;
    float log_shininess = normal_buf.w;
    float3 halfvec = normalize(normalize(CameraPosition - pos) + light);
    float3 diff = albedo_buf.xyz*max(0.0, dot(normal, light))*Color;
    float3 spec = pow(max(0.0, dot(normal, halfvec)), 10.5*exp2(log_shininess))*specular*Color;
    return min(1.0, float4((diff + spec)/att, 1.0));
}

float4 PSMSAA(VS_OUT pIn, uint iSampleIndex : SV_SAMPLEINDEX) : SV_TARGET
{
    float depth = DepthBufferMSAA.Load((int2)pIn.Position, iSampleIndex).r;
    float4 pos_screen = float4(pIn.PositionRel.xy, depth, 1.0);
    float4 albedo_buf = AlbedoBufferMSAA.Load((int2)pIn.Position, iSampleIndex);
    float4 normal_buf = NormalVectorBufferMSAA.Load((int2)pIn.Position, iSampleIndex);

    return LitGBuffer(pos_screen, albedo_buf, normal_buf);
}

float4 PS(VS_OUT pIn) : SV_TARGET
{
    float depth = DepthBuffer.Load(int3((int2)pIn.Position, 0)).r;
    float4 pos_screen = float4(pIn.PositionRel.xy, depth, 1.0);
    float4 albedo_buf = AlbedoBuffer.Load(int3((int2)pIn.Position, 0));
    float4 normal_buf = NormalVectorBuffer.Load(int3((int2)pIn.Position, 0));

    return LitGBuffer(pos_screen, albedo_buf, normal_buf);
}

technique10 MSAALighting
{
    pass P0
    {
        SetVertexShader(CompileShader(vs_4_1, VS()));
        SetGeometryShader(NULL);
        SetPixelShader(CompileShader(ps_4_1, PSMSAA()));
    }
}

technique10 StandardLighting
{
    pass P0
    {
        SetVertexShader(CompileShader(vs_4_1, VS()));
        SetGeometryShader(NULL);
        SetPixelShader(CompileShader(ps_4_1, PS()));
    }
}